package com.core.system.service.impl;

import org.apache.commons.lang3.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.core.system.dao.SystemPermissionMapper;
import com.core.system.dao.SystemRoleMapper;
import com.core.system.dao.SystemTemplateMapper;
import com.core.system.dao.SystemUserRoleMapper;
import com.core.system.service.*;
import com.core.system.utils.ConvertUtils;
import com.core.system.utils.SecurityUser;
import com.pojo.dto.PageDto;
import com.pojo.dto.SystemPermissionDto;
import com.pojo.dto.SystemRoleDto;
import com.pojo.dto.SystemTemplateDto;
import com.pojo.entity.*;
import com.pojo.req.role.PermissionInsertReq;
import com.utility.constant.Constant;
import com.utility.exception.ServiceException;
import com.utility.util.IdCreateBy;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统角色表  服务实现类
 * </p>
 *
 * @author hewei
 * @since 2020-11-26
 */
@Service
public class SystemRoleServiceImpl extends ServiceImpl<SystemRoleMapper, SystemRoleEntity> implements ISystemRoleService {


    @Autowired
    private SystemTemplateMapper systemTemplateMapper;

    @Autowired
    private SystemUserRoleMapper systemUserRoleMapper;

    @Autowired
    private SystemPermissionMapper systemPermissionMapper;

    @Autowired
    private ISystemPermissionService iSystemPermissionService;

    @Autowired
    private ISystemRolePermissionService iSystemRolePermissionService;

    @Autowired
    private ISystemTemplateService iSystemTemplateService;

    @Autowired
    private ISystemUserService iSystemUserService;



    /**
     * 获取角色权限列表
     * @return
     */
    @Override
    public List<SystemRoleDto> selectRoleList() {
        return this.baseMapper.selectRoleList();
    }


    /**
     * 根据用户名获取用户 对应的角色
     * @param roleName 用户名
     * @return
     */
    @Override
    public List<SystemRoleDto> getRole(String roleName) {
        return this.baseMapper.getUserRole(roleName);
    }




    /**
     * 查询角色列表
     * @param pageDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public IPage<SystemRoleDto> selectRolePage(PageDto pageDto) {
        IPage<SystemRoleDto> roleDtoIPage = new Page(pageDto.getPageNum(), pageDto.getPageSize());
        IPage<SystemRoleDto> systemUserDtos = this.baseMapper.selectRolePage(roleDtoIPage,pageDto);
        systemUserDtos.getRecords().forEach(e->{
            e.setCreateName(iSystemUserService.getUserName(SecurityUser.getUserId()));
            e.setUpdateName(iSystemUserService.getUserName(SecurityUser.getUserId()));
        });
        return roleDtoIPage;
    }



    /**
     * 查询角色列表
     * @param systemRoleDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SystemRoleDto selectRoleDetails(SystemRoleDto systemRoleDto) {
        verifyNull(systemRoleDto);
        verifyRoleIsExist(systemRoleDto);
        SystemRoleEntity systemRoleEntity = this.baseMapper.selectById(systemRoleDto.getId());
        List<SystemTemplateDto> templateList = getTemplateList(systemRoleEntity.getId() + "");
        BeanUtils.copyProperties(systemRoleEntity,systemRoleDto);
        systemRoleDto.setMenus(templateList);
        return systemRoleDto;
    }

    @Transactional(rollbackFor = Exception.class)
    public int updatePermission(PermissionInsertReq permissionInsertReq){
        // 查询角色关联权限
        List<SystemRolePermissionEntity> rolePermissionList = iSystemRolePermissionService.getPermissionList(permissionInsertReq.getRoleId());
        // 判断 集合的 并集 交集  判断新增和删除的数据
        List<Long> perList = rolePermissionList.stream().map(SystemRolePermissionEntity::getPermissionId).collect(Collectors.toList());
        // 对比得出 新增的角色关系
        List<Long> addTemplate = permissionInsertReq.getModuleIds().stream().filter(e -> !perList.contains(e)).collect(Collectors.toList());
        List<SystemRolePermissionEntity> list = new ArrayList<>();
        addTemplate.forEach(l ->{
            SystemRolePermissionEntity systemRolePermissionEntity = new SystemRolePermissionEntity();
            systemRolePermissionEntity.setRoleId(permissionInsertReq.getRoleId());
            systemRolePermissionEntity.setPermissionId(l);
            list.add(systemRolePermissionEntity);
        });
        iSystemRolePermissionService.saveBatch(list);

        // 对比得出 删除的角色关系
        List<Long> deleteTemplate = perList.stream().filter(e -> !permissionInsertReq.getModuleIds().contains(e)).collect(Collectors.toList());
        List<SystemRolePermissionEntity> collect = deleteTemplate.stream().map(l -> {
            SystemRolePermissionEntity systemRolePermissionEntity = new SystemRolePermissionEntity();
            systemRolePermissionEntity.setPermissionId(l);
            systemRolePermissionEntity.setRoleId(permissionInsertReq.getRoleId());
            systemRolePermissionEntity.setIsDelete(Constant.ONE);
            return systemRolePermissionEntity;
        }).collect(Collectors.toList());
        iSystemRolePermissionService.batchDelete(collect);
        return 1;
    }

    /**
     * 查询所以菜单和权限
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public List<SystemTemplateDto> getPermissionList(Long roleId){
        //查询所有有效的菜单
        List<SystemTemplateEntity> templateList = iSystemTemplateService.getTemplateList(new SystemTemplateEntity());
        List<SystemTemplateDto> templates = ConvertUtils.Convert(templateList, new SystemTemplateDto());
        // 查询所有有效的菜单权限列表
        List<SystemPermissionEntity> permissionList = iSystemPermissionService.getPermissionList();
        // 转换类型
        List<SystemPermissionDto> permissions = ConvertUtils.Convert(permissionList, new SystemPermissionDto());
        // 查询角色关联权限
        List<SystemRolePermissionEntity> rolePermissionList = iSystemRolePermissionService.getPermissionList(roleId);

        List<SystemTemplateDto> collect = templates.stream().filter(e -> Long.valueOf(Constant.ZERO).compareTo(e.getParentId()) == 0).collect(Collectors.toList());
        collect.stream().forEach(e->{

            recursionFor(e,templates,permissions,rolePermissionList);
        });
        return collect;
    }


    /**
     *  递归遍历
     *      获取顶级菜单以下的所以符合条件的菜单，
     *      封装好参数，并存储
     * @param allTemplatePojo  用于遍历的父级菜单 （这里的父级只是上层菜单，并不代表哪一级菜单）
     * @param allTemplate    全部的菜单集合
     * @param permissions    菜单的权限集合
     * @param rolePermissionList  角色绑定的权限集合
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public void recursionFor(SystemTemplateDto allTemplatePojo,List<SystemTemplateDto> allTemplate, List<SystemPermissionDto> permissions,List<SystemRolePermissionEntity> rolePermissionList){

        List<SystemTemplateDto> templateCollect = allTemplate.stream().filter(els -> els.getParentId().equals(allTemplatePojo.getId())).collect(Collectors.toList());

        //获取关联的下级菜单
        templateCollect.forEach(e->{
            /**
             *  判断是否继续递归
             */
            allTemplatePojo.setChildren(templateCollect);
            recursionFor(e, allTemplate,permissions,rolePermissionList);

        });
        if (templateCollect.isEmpty()){
            /**
             *  最下级菜单才有具体的操作权限，systemPermissionDtos集合不为空，说明当前菜单是最下级菜单，
             *  所以当前菜单的下级菜单数就等于 操作权限的集合数
             */
            List<SystemPermissionDto> systemPermissionDtoStream = permissions.stream().filter(l -> l.getTemplateId().equals(allTemplatePojo.getId())).collect(Collectors.toList());
            allTemplatePojo.setChildren(createOperateList(systemPermissionDtoStream,rolePermissionList));
        }
    }



    /**
     *  根据角色id  获取 该角色的 权限集合
     *
     *  1 得到所有的菜单列表、
     *  2 得到角色所拥有的菜单列表
     *
     *
     *
     * @param roleId
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public List<SystemTemplateDto> getTemplateList(String roleId){

        /**
         * 查询所有有效的菜单
         */
        QueryWrapper<SystemTemplateEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("is_delete",Constant.ZERO);
        List<SystemTemplateEntity> allTemplateList = systemTemplateMapper.selectList(queryWrapper);

        List<SystemTemplateDto> allTemplate = new ArrayList<>();
        allTemplateList.forEach(e->{
            SystemTemplateDto systemTemplateDto = new SystemTemplateDto();
            BeanUtils.copyProperties(e,systemTemplateDto);
            allTemplate.add(systemTemplateDto);
        });

        List<SystemTemplateDto> allTemplateCollect = allTemplate.stream().filter(e -> Long.valueOf(Constant.ZERO).compareTo(e.getParentId()) == 0).collect(Collectors.toList());

        /**
         *  根据角色id  获取角色所以关联的菜单集合
         */
        List<SystemTemplateDto> roleTemplate = systemTemplateMapper.selectTemplateRelevanceList(roleId);
        //取出菜单最上级菜单
        Map<Long, SystemTemplateDto> roleCollect = roleTemplate.stream().filter(e -> Long.valueOf(Constant.ZERO).compareTo(e.getParentId()) == 0).collect(Collectors.toMap(SystemTemplateDto::getId, Function.identity()));

        /**
         *  判断角色关联的菜单 修改选择字段类型
         */
        allTemplateCollect.forEach(e->{
            if (roleCollect.containsKey(e.getId())){
                e.setChecked(true);
            }else {
                e.setChecked(false);
            }

        });
        /**
         * 递归
         */
        allTemplateCollect.forEach(e->{
            recursionFor(e,allTemplate,roleTemplate,roleId,1);
        });
        return allTemplateCollect;
    }


    /**
     *  递归遍历
     *      获取顶级菜单以下的所以符合条件的菜单，
     *      封装好参数，并存储
     * @param allTemplatePojo  用于遍历的父级菜单 （这里的父级只是上层菜单，并不代表哪一级菜单）
     * @param allTemplate    全部的菜单集合
     * @param roleTemplate    根据角色查询的菜单集合列表
     * @param roleId    角色id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public void recursionFor(SystemTemplateDto allTemplatePojo,List<SystemTemplateDto> allTemplate, List<SystemTemplateDto> roleTemplate,String roleId,int i){

        List<SystemTemplateDto> templateDtos = new ArrayList<>();


        // 根据角色关联的菜单 获取关联的下级菜单
        List<SystemTemplateDto> roleCollectList = roleTemplate.stream().filter(e -> e.getParentId().equals(allTemplatePojo.getId())).collect(Collectors.toList());
        /**
         *   如果什么权限都没选
         *      执行查询全部菜单的方法，不然权限列表会显示空
         */
        if (i == 1 && roleCollectList.isEmpty()){
//            recursionFor(allTemplatePojo,allTemplate);
        }
        i+=1;
        int finalI = i;
        roleCollectList.forEach(e->{

            /**
             * 根据角色和菜单标签 查询出该角色拥有菜单的哪些操作权限
             *      封装操作权限存储
             */
            List<SystemPermissionDto> systemPermissionDtos = systemPermissionMapper.selectLabelPermission(e.getLabel(), roleId);

            /**
             *  最下级菜单才有具体的操作权限，systemPermissionDtos集合不为空，说明当前菜单是最下级菜单，
             *  所以当前菜单的下级菜单数就等于 操作权限的集合数
             */
//            List<SystemTemplateDto> operateList = createOperateList(e.getLabel());
//            systemPermissionDtos.forEach(ell->{
//                    operateList.forEach(el->{
//                        if (ell.getPermissionLabel().equals(el.getLabel())){
//                            el.setChecked(true);
//                        }
//                    });
//
//                });
//                e.setChildren(operateList);
            templateDtos.add(e);
            if (!templateDtos.isEmpty()){
                /**
                 * 根据 parentId 筛选出collect对象的子级菜单
                 */
                Map<Long, SystemTemplateDto> roleCollect = templateDtos.stream().filter(els -> els.getParentId().equals(allTemplatePojo.getId())).collect(Collectors.toMap(SystemTemplateDto::getId, Function.identity()));

                List<SystemTemplateDto> templateCollect = allTemplate.stream().filter(els -> els.getParentId().equals(allTemplatePojo.getId())).collect(Collectors.toList());
                /**
                 * 判断下级菜单选中状态
                 *  选中存储保持的操作权限
                 *  下级菜单没有选中操作权限肯定为空
                 */
                templateCollect.forEach(ela->{
                    if (roleCollect.containsKey(ela.getId())){
                        ela.setChecked(true);
                        ela.setChildren(roleCollect.get(ela.getId()).getChildren());
                    }else {
                        ela.setChecked(false);
//                        ela.setChildren(createOperateList(ela.getLabel()));
                    }
                });
                allTemplatePojo.setChildren(templateCollect);

            }
            /**
             *  判断是否继续递归
             */
            if (!roleCollectList.isEmpty()){
                roleCollectList.forEach(el->{
                    recursionFor( el, allTemplate,templateDtos,roleId, finalI);
                });
            }
        });
    }

    /**
     * 生成操作集合
     * @return
     */
    public List<SystemTemplateDto> createOperateList(List<SystemPermissionDto> permissionList,List<SystemRolePermissionEntity> rolePermissionList){
        List<SystemTemplateDto> temList = new ArrayList();
        permissionList.forEach(l ->{
            SystemTemplateDto systemTemplateDto = new SystemTemplateDto();
            boolean isChecked = rolePermissionList.stream().anyMatch(n -> n.getPermissionId().equals(l.getId()));
            systemTemplateDto.setName(l.getPermissionName());
            systemTemplateDto.setSort((short) 1);
            systemTemplateDto.setChecked(isChecked);
            systemTemplateDto.setId(l.getId());
            temList.add(systemTemplateDto);
        });
        return temList;
    }




    /**
     * 编辑角色启动状态
     *      判断角色是否存在
     *      判断角色是否被关联用户使用,如被使用则不可删除
     *      存在，并且为被使用则可以编辑状态
     * @param systemRoleDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateStatus(SystemRoleDto systemRoleDto){
        verifyRoleIsExist(systemRoleDto);
        verifyRoleIsRelevanceUser(systemRoleDto);
        return  this.baseMapper.updateById(systemRoleDto);
    };

    /**
     *  修改角色信息
     * @param systemRoleDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateRole(SystemRoleDto systemRoleDto) {
        /**
         *  公共判断
         */
        verifyRoleIsExist(systemRoleDto);
        verifyField( systemRoleDto);
        verifyNull( systemRoleDto);
        // 修改角色信息
        this.baseMapper.updateById(systemRoleDto);
        return 1;
    }



    /**
     * 新增用户信息
     * @param systemRoleDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertRole(SystemRoleDto systemRoleDto) {
        verifyField( systemRoleDto);
        Long roleId = IdCreateBy.getById();
        systemRoleDto.setId(roleId);
        return this.baseMapper.insert(systemRoleDto);
    }





    /**
     * 删除角色
     * @param systemRoleDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteRole(SystemRoleDto systemRoleDto) {
        verifyNull( systemRoleDto);
        /**
         *  已有关联用户不允许删除
         */
        verifyRoleIsRelevanceUser(systemRoleDto);
        /**
         * 删除 用户角色关联表
         */
        LambdaQueryWrapper<SystemUserRoleEntity> roleEntityQueryWrapper = new LambdaQueryWrapper<>();
        roleEntityQueryWrapper.eq(SystemUserRoleEntity::getRoleId,systemRoleDto.getId());
        SystemUserRoleEntity systemUserRoleEntity = new SystemUserRoleEntity();
        systemUserRoleEntity.setIsDelete(Constant.ONE);
        systemUserRoleMapper.update(systemUserRoleEntity,roleEntityQueryWrapper);
        /**
         * 删除角色
         */
        systemRoleDto.setIsDelete(Constant.ONE);
        return this.baseMapper.updateById(systemRoleDto);
    }



    /**
     * 批量删除角色
     * @param systemRoleDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchDeleteRole(SystemRoleDto systemRoleDto) {
        if (!StringUtils.isNotBlank(systemRoleDto.getIds())){
            throw new ServiceException("未选择删除的角色");
        }
        /**
         *  已有关联用户不允许删除
         */
        List<String> ids = Arrays.asList(systemRoleDto.getIds().split(","));
        QueryWrapper<SystemUserRoleEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("role_id", ids);
        queryWrapper.eq("is_delete",Constant.ZERO);
        if (!systemUserRoleMapper.selectList(queryWrapper).isEmpty()){
            throw new ServiceException("选择的角色已被用户使用无法停用,请先修改关联用户角色");
        }
        /**
         * 批量删除 用户角色关联表
         */
        QueryWrapper<SystemUserRoleEntity> roleEntityQueryWrapper = new QueryWrapper<>();
        roleEntityQueryWrapper.in("role_id", ids);
        SystemUserRoleEntity systemUserRoleEntity = new SystemUserRoleEntity();
        systemUserRoleEntity.setIsDelete(Constant.ONE);
        systemUserRoleMapper.update(systemUserRoleEntity,roleEntityQueryWrapper);
        /**
         * 批量删除角色
         */
        QueryWrapper<SystemRoleEntity> roleEntity = new QueryWrapper<>();
        roleEntity.in("id", ids);
        systemRoleDto.setIsDelete(Constant.ONE);
        return this.baseMapper.update(systemRoleDto,roleEntity);
    }





    /**
     * 判断 角色id不能为空
     * @param systemRoleDto
     */
    public void verifyNull(SystemRoleDto systemRoleDto){
        if (!StringUtils.isNotBlank(systemRoleDto.getId()+"")){
            throw new ServiceException("角色id不能为空");
        }
    }

    /**
     * 判断 角色不存在
     * @param systemRoleDto
     */
    @Transactional(rollbackFor = Exception.class)
    public void verifyRoleIsExist(SystemRoleDto systemRoleDto){
        SystemRoleEntity systemRoleEntity = this.baseMapper.selectById(systemRoleDto.getId());
        if (null == systemRoleEntity){
            throw new ServiceException("角色不存在");
        }
    }



    /**
     * 判断角色名称不能重复
     * @param systemRoleDto
     */
    @Transactional(rollbackFor = Exception.class)
    public void verifyField(SystemRoleDto systemRoleDto){
        SystemRoleEntity systemRoleEntity = this.baseMapper.selectById(systemRoleDto.getId());
        /**
         * 判断 id不为空 并且 角色名称相同  角色id也相同 表示是同一条数据 不做名称判断去重
         * 如果 id不为空 角色名称相同 角色id不相同 在名称去重判断
         */
        if (null != systemRoleDto.getId() && !systemRoleDto.getRoleName().equals(systemRoleEntity.getRoleName())){
            LambdaQueryWrapper<SystemRoleEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SystemRoleEntity::getRoleName,systemRoleDto.getRoleName());
            queryWrapper.eq(SystemRoleEntity::getIsDelete,Constant.ZERO);
            List<SystemRoleEntity> systemRoleEntities = this.baseMapper.selectList(queryWrapper);
            if (!systemRoleEntities.isEmpty()){
                throw new ServiceException("角色名称已存在");
            }
        }


    }

    /**
     * 判断是否有用户角色关联数据
     * @param systemRoleDto
     * @return
     */
    public void verifyRoleIsRelevanceUser(SystemRoleDto systemRoleDto){
        LambdaQueryWrapper<SystemUserRoleEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SystemUserRoleEntity::getRoleId,systemRoleDto.getId());
        queryWrapper.eq(SystemUserRoleEntity::getIsDelete,Constant.ZERO);
        if (!systemUserRoleMapper.selectList(queryWrapper).isEmpty()){
            throw new ServiceException("角色已被用户使用无法停用,请先修改关联用户角色");
        }
    }
}
